export interface Vnode {
  tag: string;
  data: any;
  value: unknown;
  type: number;
  child?: Vnode;
  parent?: Vnode;
  finish?: boolean;
  sibling?: Vnode;
  pre?: Vnode;
  dom?: HTMLElement;
}
const getClientHeight: (dom: Element) => number = (dom) => {
  const style = window.getComputedStyle(dom, null);
  return (
    Number.parseFloat(style.height) +
    Number.parseFloat(style.marginTop) +
    Number.parseFloat(style.marginBottom)
  );
};
// 创建VDom类
class VDom {
  tag: string;
  data: Record<string, any> | undefined;
  value: unknown;
  type: number;
  child?: Vnode;
  parent?: Vnode;
  sibling?: Vnode;
  pre?: Vnode;
  constructor(
    tag: string,
    data: Record<string, any> | undefined,
    value: unknown,
    type: number,
    child?: Vnode,
    parent?: Vnode,
    sibling?: Vnode,
    pre?: Vnode
  ) {
    this.tag = tag && tag.toLowerCase(); // 节点名
    this.data = data; // 属性
    this.value = value; // 文本数据
    this.type = type; // 节点类型
    this.child = child || undefined;
    this.parent = parent;
    this.sibling = sibling;
    this.pre = pre;
  }
}

class GetPage {
  pages: Record<string, any>;
  pages_body: Record<string, any>;
  data_section: Record<string, any>;
  current_page: number;
  container: HTMLElement | null = null;
  rootVnode: Vnode | null = null;
  part = "left";
  constructor() {
    this.pages = {};
    this.pages_body = {};
    this.data_section = {};
    this.current_page = 0;
  }

  doWork(d: Vnode) {
    if (d.parent) {
      this.getDom(d.parent).appendChild(this.getDom(d, true));
    }
    return d.child;
  }

  getVNode(node: HTMLElement, parent?: Vnode) {
    const run = (
      node: HTMLElement,
      parent?: Vnode,
      stopBySection?: boolean
    ) => {
      const nodeType = node.nodeType;
      let _vnode = null;
      const pre: any = null;
      if (nodeType === 1) {
        // 元素
        const tag = node.tagName;
        const attrs = node.attributes;
        const _attrObj: any = {};
        for (let i = 0; i < attrs.length; i++) {
          _attrObj[attrs[i].name] = attrs[i].value;
        }

        _vnode = new VDom(
          tag,
          _attrObj,
          undefined,
          nodeType,
          undefined,
          parent
        );
        if (stopBySection && _attrObj["data-section"]) {
          this.data_section[_attrObj["data-section"]] = node;
          return _vnode;
        }
        const children = Array.from(node.childNodes || []).filter(
          (c) => c.nodeType === 1 || c.nodeType === 3
        );
        let child: any = null;
        for (let i = 0; i < children.length; i++) {
          if (i === 0) {
            child = run(children[i] as HTMLElement, _vnode, stopBySection);
            _vnode.child = child;
          } else {
            if (child) {
              child!.sibling = run(
                children[i] as HTMLElement,
                _vnode,
                stopBySection
              );
              if (child!.sibling) {
                child!.sibling.pre = child;
              }

              child = child!.sibling;
            }
          }
        }
      } else if (nodeType === 3) {
        // 文本
        _vnode = new VDom(
          node.tagName,
          undefined,
          node.nodeValue,
          nodeType,
          undefined,
          parent,
          pre
        );
      } else {
        _vnode = new VDom(
          node.tagName,
          undefined,
          node.nodeValue,
          nodeType,
          undefined,
          parent,
          pre
        );
      }
      return _vnode as VDom;
    };
    this.rootVnode = run(node, undefined, true);
    Object.keys(this.data_section).forEach((item) => {
      this.data_section[item] = run(this.data_section[item], undefined, false);
    });
  }

  deleteFinishedChild(current: any, root: any) {
    // 没有子节点，也没有兄弟节点，向上走
    while (!current.sibling) {
      if (!current.parent || current.parent === root) {
        return;
      }
      // 向上走，直到找兄弟节点
      if (current.finish) {
        // current.parent.child = current.sibling
        // if (!current.data?.class?.includes('leftSection')) {
        current.parent.child = current.sibling;
        // }
        // else {
        //   console.log(current.data)
        // }
      }
      current = current.parent;
    }

    // 找到了兄弟节点，将其设为active node，走下一次循环
    current = current.sibling;
  }

  deleteFinishedNode(current: any) {
    // 没有子节点，也没有兄弟节点，向上走
    if (current.tag === "li" && current.data.value === "32") {
      // debugger
    }
    if (current.sibling) {
      if (current.pre) {
        current.pre.sibling = current.sibling;
      } else {
        current.parent!.child = current.sibling;
      }
      return current.sibling;
    } else {
      if (current.pre) {
        current.pre.sibling = null;
        return current.pre;
      } else {
        current.parent!.child = null;
        return current.parent;
      }
    }

    // while (current) {
    //   if (current.finish) {
    //     current.parent!.child = current.sibling
    //   }
    //   current = current.sibling
    // }
  }

  deleteFinishedChild2(current: any) {
    // console.log('---', current);
    // 没有子节点，也没有兄弟节点，向上走
    current = current.child;
    while (current) {
      if (current.finish) {
        current.parent!.child = current.sibling;
      }
      current = current.sibling;
    }
  }

  truncateText(
    textContent: string,
    element: HTMLElement,
    rootDom: HTMLElement
  ) {
    const left = 0;
    const right = textContent.length;
    let truncatedContent = "";
    if (right === 1) {
      element.textContent = textContent.slice(1);
      truncatedContent = textContent.slice(0);
      return truncatedContent;
    }
    check(left, right);
    function check(left: number, right: number) {
      if (right - left <= 1) {
        return;
      }
      const mid = Math.round((left + right) / 2);
      element.textContent = textContent.slice(0, mid + 1);
      truncatedContent = textContent.slice(mid + 1);
      if (rootDom.scrollHeight <= rootDom.offsetHeight) {
        check(mid, right);
      } else {
        if (mid - left <= 1) {
          left--;
        }
        check(left, mid);
      }
    }

    return truncatedContent;
  }

  isBlockChild(current: any, root: any) {
    if (current.data?.["data-type"] === "block") {
      return false;
    }
    while (current) {
      if (!current || current === root) {
        return false;
      }
      if (current.data?.["data-type"] === "block") {
        return current;
      }
      current = current.parent;
    }
    // 找到了兄弟节点，将其设为active node，走下一次循环
  }

  removePaddingProperty(node: Vnode) {
    let current = node;

    while (current) {
      if (current.data && !current.data["data-section"]) {
        Object.keys(current.data).forEach((key) => {
          if (key === "style") {
            current.data[key] = current.data[key]
              .split(";")
              .filter(
                (t: any) =>
                  !t.includes("margin-top") && !t.includes("padding-top")
              )
              .join(";");
          }
        });
      }

      current = current.parent as Vnode;
    }
  }

  hideLiStyle(node) {
    let current = node;

    while (current) {
      if (current.tag === "li") {
        if (current.data.style) {
          current.data.style = `${current.data.style};list-style:none;`;
        } else {
          current.data.style = `list-style:none;`;
        }
      }
      current = current.parent as Vnode;
    }
  }

  walk(root: Vnode, pageSection: string) {
    this.container!.innerHTML = "";
    const pageWraper = this.pages[this.current_page];
    root.dom = pageWraper[pageSection];
    this.container?.appendChild(pageWraper.root);
    let current = root;
    while (true) {
      this.deleteFinishedChild2(current);
      const child = this.doWork(current);
      if (pageWraper.root?.scrollHeight > pageWraper.root?.offsetHeight) {
        const element = this.getDom(current.parent).lastChild;
        const block = this.isBlockChild(current, root);
        if (block) {
          block.dom.parentNode.removeChild(block.dom);
        } else if (current.type === 3) {
          const textContent = element.textContent;
          const truncatedContent = this.truncateText(
            textContent,
            element,
            pageWraper.root
          );
          if (truncatedContent.length) {
            current.value = truncatedContent;
            this.removePaddingProperty(current);
            this.hideLiStyle(current);
          }
        } else {
          element.parentNode.removeChild(element);
        }
        this.current_page++;
        this.setPages();
        this.walk(root, pageSection);
        return;
      } else {
        // const blockChild = this.isBlockChild(current, root)
        // const blockChild = this.isBlockChild(current, root)
        // if (blockChild && blockChild === current) {
        //   current.finish = true
        // }
      }
      // 如果存在子节点，将其设为active node，走下一次循环

      if (child) {
        current = child;
        continue;
      } else {
        current.finish = true;
      }

      // 如果返回到了顶端，退出函数
      if (current === root) {
        return;
      }
      // 没有子节点，也没有兄弟节点，向上走

      while (!current.sibling) {
        if (!current.parent || current.parent === root) {
          return;
        }
        // 向上走，直到找兄弟节点

        current = current.parent;
        const blockChild = this.isBlockChild(current, root);
        if (!blockChild && current.data?.["data-type"] !== "keep") {
          current.finish = true;
        }

        if (current.data?.["data-type"] === "block") {
          if (current.pre) {
            current.pre.sibling = current.sibling;
          } else {
            current.parent!.child = current.sibling;
          }
        }
        if (
          current.parent?.data?.["data-type"] !== "block" &&
          !this.isBlockChild(current, root)
        ) {
          if (current.data?.["data-type"] !== "keep") {
            current.parent!.child = current.sibling;
          }
        }
      }
      // 找到了兄弟节点，将其设为active node，走下一次循环

      current = current.sibling;
    }
  }

  getPageWraperByVnode(root: Vnode) {
    let current = root;
    const obj: any = {};
    while (true) {
      let child;
      if (!current.data?.["data-section"]) {
        child = this.doWork(current);
      } else {
        current.dom =
          this.pages[this.current_page][current.data?.["data-section"]];
        if (current.dom) {
          current.parent?.dom?.appendChild(current.dom as HTMLElement);
          child = current.child;
        } else {
          child = this.doWork(current);
        }
        obj[current.data?.["data-section"]] = current.dom;
        if (!current.sibling) {
          return obj;
        }
        current = current.sibling;
        continue;
      }

      if (child) {
        current = child;
        continue;
      }

      // 如果返回到了顶端，退出函数
      if (current === root) {
        return;
      }
      if (current.sibling && current.finish) {
        current.parent!.child = current.sibling;
      }
      // 没有子节点，也没有兄弟节点，向上走
      while (!current.sibling) {
        if (!current.parent || current.parent === root) {
          return;
        }
        // 向上走，直到找兄弟节点
        current = current.parent;
        current.parent!.child = current.sibling;
      }
      // 找到了兄弟节点，将其设为active node，走下一次循环
      current = current.sibling;
    }
  }

  setPages() {
    if (!this.pages[this.current_page]) {
      this.pages[this.current_page] = {};
    }
    const classname = this.rootVnode.data.class
      .split(" ")
      .filter((item) => !item.startsWith("paper"))
      .join(" ");
    this.rootVnode.data.class = `${classname} paper${this.current_page}`;
    const rootDom = this.getDom(this.rootVnode, true);
    const res = this.getPageWraperByVnode(this.rootVnode as Vnode);
    this.pages[this.current_page] = {
      ...this.pages[this.current_page],
      root: rootDom,
      ...res,
    };
  }

  parseVNode(container: any) {
    this.container = container;
    this.current_page = 0;
    this.setPages();
    Object.keys(this.data_section).forEach((item) => {
      this.current_page = 0;
      this.walk(this.data_section[item], item);
    });
    return this.pages;
  }

  getDom(node: any, needRegenerate?: boolean) {
    if (!needRegenerate && node.dom) {
      return node.dom;
    }
    const type = node.type;
    let rdom = null;

    if (type === 1) {
      rdom = document.createElement(node.tag);
      // 元素
      const attrs = node.data;
      for (const key in attrs) {
        rdom.setAttribute(key, attrs[key]);
      }
    } else if (type === 3) {
      // 文本
      rdom = document.createTextNode(node.value);
    }
    node.dom = rdom;
    return rdom;
  }
}
export { GetPage, getClientHeight };
